﻿#pragma once

/************************************************************************/
/* 
	锁相关
	1，mutex
	2，semaphore
	3，
*/
/************************************************************************/

#include "common.h"
#include <queue>
#include "time_util.h"


#ifdef _WIN32
#define MUTEX_WAIT_INFINITE INFINITE
#define ykit_mutex_t HANDLE
#else
#define MUTEX_WAIT_INFINITE UINT_MAX
#define ykit_mutex_t pthread_mutex_t
#endif

#ifdef _WIN32
#define SEMA_WAIT_INFINITE INFINITE
#define ykit_sem_t HANDLE
#else
#define SEMA_WAIT_INFINITE UINT_MAX
#define ykit_sem_t sem_t
#endif

class CYKMutex
{
public:
	CYKMutex()
	{
#ifdef _WIN32
	_mutex = CreateMutex(NULL, FALSE, NULL);
#else
		int32_t ret = 0;
		pthread_mutexattr_t attr;

		ret = pthread_mutexattr_init(&attr);
		if (0 != ret) {
			ret = pthread_mutex_init(&this->_mutex, NULL);
		}
		else {
			ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
			ret = pthread_mutex_init(&_mutex, &attr);
			pthread_mutexattr_destroy(&attr);
		}
#endif
	}
	~CYKMutex()
	{

#ifdef _WIN32
		BOOL ret = CloseHandle(_mutex);
		if (0 != ret) {
			_mutex = NULL;
		}
#else
		pthread_mutex_destroy(&_mutex);
#endif
	}
public:
	int32_t lock(int millisecond = MUTEX_WAIT_INFINITE)
	{

#ifdef _WIN32
		if (NULL == _mutex) {
			return E_NULL_POINTER;
		}

		DWORD ret = WaitForSingleObject(_mutex, millisecond);
		if (WAIT_OBJECT_0 == ret) {
			return 0;
		}
		else if (WAIT_TIMEOUT == ret) {
			return E_TIMEOUT;
		}
		else {
			return E_SYSERROR;
		}
#else
		int32_t ret = 0;

		if (MUTEX_WAIT_INFINITE == millisecond) {
			ret = pthread_mutex_lock(&_mutex);
		}
		else {
			struct timespec ts = { 0, 0 };
			TimeUtil::get_abs_timespec(&ts, millisecond);
			ret = pthread_mutex_timedlock(&_mutex, &ts);
		}

		if (0 != ret) {
			int32_t e = OCGetLastError();
			if (ETIMEDOUT == e) {
				return E_TIMEOUT;
			}
			else {
				return E_SYSERROR;
			}
		}
		return 0;
#endif
	}
	int32_t try_lock()
	{

#ifdef _WIN32
		return lock(1);
#else
		int32_t ret = 0;
		ret = pthread_mutex_trylock(&_mutex);
		return (0 == ret ? 0 : E_SYSERROR);
#endif
	}
	int32_t unlock()
	{

#ifdef _WIN32
		BOOL ret = FALSE;

		if (NULL != _mutex) {
			ret = ReleaseMutex(_mutex);
		}
		return (0 != ret ? 0 : E_SYSERROR);
#else
		int32_t ret = 0;
		ret = pthread_mutex_unlock(&_mutex);
		return (0 == ret ? 0 : E_SYSERROR);
#endif
	}
private:
	CYKMutex(CYKMutex&);
	CYKMutex&operator=(const CYKMutex&);

private:
	ykit_mutex_t	_mutex;
};

template <typename T>
class CYKAutoLock{
public:
	explicit CYKAutoLock(T*pt)
		:m_pt(pt)
		, m_locked(0)
	{
		if (m_pt && m_pt->lock() == 0)
		{
			m_locked = true;
		}
	}

	~CYKAutoLock()
	{
		if (m_pt && m_pt->unlock() == 0)
		{
			m_locked = false;
		}
	}

	bool isLocked() const
	{
		return m_locked;
	}

private:
	volatile bool	m_locked;		//多线程访问，不从寄存器(cache)而从内存读取
	T*				m_pt;
};
typedef CYKAutoLock<CYKMutex> CYKAutoMutex;

/*信号量*/
class CYKSemaphore
{
public:
	~CYKSemaphore(){

#ifdef _WIN32
		if (NULL != m_sema) {
			BOOL ret = CloseHandle(m_sema);
			if (0 != ret) {
				m_sema = NULL;
			}
		}
#else
		sem_destroy(&m_sema);
#endif
	}
	/*信号量的初始值*/
	CYKSemaphore(int32_t ninit = 0)
	{
		if (ninit < 0) {
			ninit = 0;
		}
#ifdef _WIN32
		m_sema = CreateSemaphore(NULL, ninit, LONG_MAX, NULL);
#else
		sem_init(&m_sema, 0, ninit);
#endif
	}

	/*等待信号量*/
	int32_t wait(uint32_t millisecond = SEMA_WAIT_INFINITE)
	{

#ifdef _WIN32
		if (NULL == m_sema) {
			return E_NULL_POINTER;
		}

		DWORD ret = WaitForSingleObject(m_sema, millisecond);
		if (WAIT_OBJECT_0 == ret || WAIT_ABANDONED == ret) {
			return 0;
		}
		else if (WAIT_TIMEOUT == ret) {
			return E_TIMEOUT;
		}
		else {
			return E_SYSERROR;
		}
#else
		int32_t ret = 0;

		if (SEMA_WAIT_INFINITE == millisecond) {
			while ((ret = sem_wait(&m_sema)) == -1 && EINTR == errno);
		}
		else{
			struct timespec ts = { 0, 0 };
			TimeUtil::get_abs_timespec(&ts, millisecond);
			while ((ret = sem_timedwait(&m_sema, &ts)) == -1 && EINTR == errno);
		}

		if (0 != ret){
			if (OCGetLastError() == ETIMEDOUT){
				return E_TIMEOUT;
			}
			else{
				return E_SYSERROR;
			}
		}

		return 0;
#endif
	}
	bool try_wait()
	{

#ifdef _WIN32
		if (NULL == m_sema) {
			return false;
		}

		DWORD ret = WaitForSingleObject(m_sema, 0);
		if (WAIT_OBJECT_0 == ret || WAIT_ABANDONED == ret) {
			return true;
		}

		return false;
#else
		int32_t ret = 0;
		while ((ret = sem_trywait(&m_sema)) == -1 && EINTR == errno);
		return (0 == ret);
#endif
	}
	/*触发信号量*/
	int32_t signal()
	{

#ifdef _WIN32
		BOOL ret = FALSE;

		if (NULL != m_sema) {
			ret = ReleaseSemaphore(m_sema, 1, NULL);
		}
		return (0 != ret ? 0 : E_SYSERROR);
#else

		int32_t ret = 0;
		while ((ret = sem_post(&m_sema)) == -1 && EINTR == errno);
		return (0 == ret ? 0 : E_SYSERROR);

#endif
	}

private:
	ykit_sem_t	m_sema;
};

/*读写锁*/
class CYKRWLock
{
public:

#ifdef _WIN32
	CYKRWLock() :_reader_num(0), _writer_num(0), _writer_waiting_num(0){
		_mutex = CreateMutex(NULL, FALSE, NULL);
		_evt_reader = CreateEvent(NULL, TRUE, TRUE, NULL);
		_evt_writer = CreateEvent(NULL, TRUE, TRUE, NULL);
	}
	~CYKRWLock()
	{
		CloseHandle(_mutex);
		CloseHandle(_evt_reader);
		CloseHandle(_evt_writer);
	}
#else
	CYKRWLock(){
		pthread_rwlock_init(&_rwlock, NULL);
	}

	~CYKRWLock()
	{
		pthread_rwlock_unlock(&_rwlock);
	}
#endif
	
	int32_t get_rdlock()
	{
#ifdef _WIN32
		HANDLE h[2];
		h[0] = _mutex;
		h[1] = _evt_reader;
		//同时等待互斥锁和读者信号
		switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
		{
		case WAIT_OBJECT_0:
		case WAIT_OBJECT_0 + 1:
			//if(_writer_num == 0)
			//{
			_reader_num++;
			ResetEvent(_evt_writer);
			//}
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			return -1;
		}
		return 0;
#else
		return pthread_rwlock_rdlock(&_rwlock);
#endif
	}
	int32_t try_rdlock()
	{
#ifdef _WIN32
		HANDLE h[2];
		h[0] = _mutex;
		h[1] = _evt_reader;
		//同时等待互斥锁和读者信号，仅等待1毫秒
		switch (WaitForMultipleObjects(2, h, TRUE, 1))
		{
		case WAIT_OBJECT_0:
		case WAIT_OBJECT_0 + 1:
			//if(_writer_num == 0)
			//{
			_reader_num++;
			ResetEvent(_evt_writer);
			//}
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			return -1;
		}
		return 0;
#else
		return pthread_rwlock_tryrdlock(&_rwlock);

#endif
	}
	int32_t get_wrlock()
	{
#ifdef _WIN32
		//增加写者记录
		add_writer();
		HANDLE h[2];
		h[0] = _mutex;
		h[1] = _evt_writer;
		//同时等待互斥锁和写者信号，仅等待1毫秒
		switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
		{
		case WAIT_OBJECT_0:
		case WAIT_OBJECT_0 + 1:
			//记录写者数目，关闭读者写者信号
			_writer_num++;
			_writer_waiting_num--;
			ResetEvent(_evt_reader);
			ResetEvent(_evt_writer);
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			//加锁不成功，需要删除等待写者记录
			remove_writer();
			return -1;
		}
		return 0;
#else
		return pthread_rwlock_wrlock(&_rwlock);

#endif
	}
	int32_t try_wrlock()
	{
#ifdef _WIN32
		//增加写者记录
		add_writer();
		HANDLE h[2];
		h[0] = _mutex;
		h[1] = _evt_writer;
		//同时等待互斥锁和写者信号，仅等待1毫秒
		switch (WaitForMultipleObjects(2, h, TRUE, 1))
		{
		case WAIT_OBJECT_0:
		case WAIT_OBJECT_0 + 1:
			//记录写者数目，关闭读者写者信号
			_writer_num++;
			_writer_waiting_num--;
			ResetEvent(_evt_reader);
			ResetEvent(_evt_writer);
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			//加锁不成功，需要删除等待写者记录
			remove_writer();
			return -1;
		}
		return 0;
#else
		return pthread_rwlock_trywrlock(&_rwlock);

#endif

	}
	int32_t unlock()
	{
#ifdef _WIN32
		//获取互斥锁即可
		switch (WaitForSingleObject(_mutex, INFINITE))
		{
		case WAIT_OBJECT_0:
			if (_writer_num == 0)
			{
				//可能释放的是读锁
				if (_reader_num > 0)
				{
					//只有读锁被占有，释放的是读锁。否则认为释放错误
					_reader_num--;
					if (_reader_num == 0)
					{
						SetEvent(_evt_writer);
					}
				}
				else
				{
					//没有人获得读锁或写锁，认为失败
					return -1;
				}
			}
			else
			{
				//释放的一定是写锁
				_writer_num = 0;
				if (_writer_waiting_num == 0)
				{
					//没有等待的写者，开启读者和写者信号
					SetEvent(_evt_reader);
					SetEvent(_evt_writer);
				}
				else
				{
					//有等待的写者，优先进行写操作
					SetEvent(_evt_writer);
				}
			}
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			return -1;
		}
		return 0;
#else
		return pthread_rwlock_unlock(&_rwlock);

#endif
	}
private:
#ifdef _WIN32
	void add_writer()
	{
		//获取互斥锁即可
		switch (WaitForSingleObject(_mutex, INFINITE))
		{
		case WAIT_OBJECT_0:
			_writer_waiting_num++;
			//若有人等待写锁，关闭读者信号，不允许有读者抢先
			if (_writer_waiting_num > 0)
			{
				ResetEvent(_evt_reader);
			}
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			break;
		}
	}
	void remove_writer()
	{
		//获取互斥锁即可
		switch (WaitForSingleObject(_mutex, INFINITE))
		{
		case WAIT_OBJECT_0:
			_writer_waiting_num--;
			//若已经没有等待的写者，开启读者信号
			if (_writer_waiting_num == 0)
			{
				SetEvent(_evt_reader);
			}
			ReleaseMutex(_mutex);
			break;
		default:
			ReleaseMutex(_mutex);
			break;
		}
	}
	HANDLE _mutex;                  /**< 互斥锁       */
	HANDLE _evt_reader;             /**< 读者事件     */
	HANDLE _evt_writer;             /**< 写者事件     */

	int32_t _reader_num;            /**< 当前拿到锁的读者   */
	int32_t _writer_num;            /**< 当前拿到锁的写者   */
	int32_t _writer_waiting_num;    /**< 当前排队拿写锁的人数  */

#else
pthread_rwlock_t _rwlock;       /**< Linux的读写锁      */
#endif
};